#!/usr/bin/env python3
"""
Three-Player Chinese Chess (Xiangqi) Game - PyQt6 Implementation

This application implements a three-player variant of Chinese chess with:
- Three 9x5 game boards arranged in triangular formation
- Three players: Red, Blue, and Green
- Modified piece placement for smaller boards
- Cross-board movement capabilities
- Turn-based gameplay with three players
- Win condition detection
- Game reset functionality
"""

import sys
import math
from enum import Enum
from typing import Optional, List, Tuple, Dict
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QPushButton, QLabel, QTextEdit, QMessageBox, QMenuBar, QStatusBar,
    QGroupBox, QSplitter
)
from PyQt6.QtCore import Qt, pyqtSignal, QPointF, QRectF
from PyQt6.QtGui import QPainter, QPen, QBrush, QFont, QAction, QColor, QPainterPath
from PyQt6.QtWidgets import QFrame


class PieceType(Enum):
    """Chinese chess piece types"""
    GENERAL = "general"      # 帥/將
    ADVISOR = "advisor"      # 仕/士  
    ELEPHANT = "elephant"    # 相/象
    HORSE = "horse"          # 馬/马
    CHARIOT = "chariot"      # 車/车
    CANNON = "cannon"        # 炮/砲
    PAWN = "pawn"           # 兵/卒


class Player(Enum):
    """Players in the game"""
    RED = "red"
    BLUE = "blue"
    GREEN = "green"


class BoardPosition:
    """Represents a position on one of the three boards"""
    def __init__(self, board_id: int, row: int, col: int):
        self.board_id = board_id  # 0 for Red, 1 for Blue, 2 for Green
        self.row = row
        self.col = col
        
    def __eq__(self, other):
        if isinstance(other, BoardPosition):
            return (self.board_id == other.board_id and 
                   self.row == other.row and 
                   self.col == other.col)
        return False
        
    def __str__(self):
        board_names = ["Red", "Blue", "Green"]
        return f"{board_names[self.board_id]}({self.row},{self.col})"


class ChessPiece:
    """Represents a Chinese chess piece"""
    
    # Chinese characters for pieces
    PIECE_CHARS = {
        Player.RED: {
            PieceType.GENERAL: "帥",
            PieceType.ADVISOR: "仕",
            PieceType.ELEPHANT: "相",
            PieceType.HORSE: "馬",
            PieceType.CHARIOT: "車",
            PieceType.CANNON: "炮",
            PieceType.PAWN: "兵"
        },
        Player.BLUE: {
            PieceType.GENERAL: "將",
            PieceType.ADVISOR: "士",
            PieceType.ELEPHANT: "象",
            PieceType.HORSE: "马",
            PieceType.CHARIOT: "车",
            PieceType.CANNON: "砲",
            PieceType.PAWN: "卒"
        },
        Player.GREEN: {
            PieceType.GENERAL: "王",
            PieceType.ADVISOR: "侍",
            PieceType.ELEPHANT: "像",
            PieceType.HORSE: "騎",
            PieceType.CHARIOT: "輛",
            PieceType.CANNON: "炮",
            PieceType.PAWN: "兵"
        }
    }
    
    def __init__(self, piece_type: PieceType, player: Player, position: BoardPosition):
        self.piece_type = piece_type
        self.player = player
        self.position = position
        
    def get_char(self) -> str:
        """Get the Chinese character for this piece"""
        return self.PIECE_CHARS[self.player][self.piece_type]
        
    def __str__(self):
        return f"{self.player.value} {self.piece_type.value} at {self.position}"


class ThreePlayerChessBoard(QFrame):
    """Three-player chess board widget that handles display and interaction"""
    
    piece_moved = pyqtSignal(BoardPosition, BoardPosition)
    
    def __init__(self):
        super().__init__()
        self.setFixedSize(800, 800)
        self.setFrameStyle(QFrame.Shape.Box)
        
        # Board dimensions for each player's board
        self.rows = 9  # 9 rows
        self.cols = 5  # 5 columns
        self.cell_size = 40
        self.board_width = (self.cols - 1) * self.cell_size
        self.board_height = (self.rows - 1) * self.cell_size
        
        # Center of the widget
        self.center_x = 400
        self.center_y = 400
        
        # Distance from center to board centers
        self.board_distance = 200
        
        # Board angles (0, 120, 240 degrees)
        self.board_angles = [0, 120, 240]
        
        # Board colors
        self.board_colors = {
            0: QColor(255, 200, 200),  # Red
            1: QColor(200, 200, 255),  # Blue
            2: QColor(200, 255, 200)   # Green
        }
        
        # Player mapping
        self.board_to_player = {0: Player.RED, 1: Player.BLUE, 2: Player.GREEN}
        self.player_to_board = {Player.RED: 0, Player.BLUE: 1, Player.GREEN: 2}
        
        # Game state - 3 boards, each 9x5 (but accessed as [col][row] for piece placement)
        self.boards: List[List[List[Optional[ChessPiece]]]] = [
            [[None for _ in range(self.rows)] for _ in range(self.cols)]
            for _ in range(3)
        ]
        
        self.selected_piece: Optional[ChessPiece] = None
        self.selected_pos: Optional[BoardPosition] = None
        self.current_player = Player.RED
        self.eliminated_players = set()
        self.game_over = False
        
        self.setup_initial_boards()
        
    def setup_initial_boards(self):
        """Setup the initial chess boards with pieces"""
        # Clear all boards
        for board_id in range(3):
            for col in range(self.cols):
                for row in range(self.rows):
                    self.boards[board_id][col][row] = None
                    
        # Setup pieces for each player - traditional Chinese chess distribution for 9×5 boards
        # Pieces are placed at the outer boundary using transposed indexing [col][row]
        for board_id, player in self.board_to_player.items():
            # Outer column (col 0) - Traditional arrangement: 車馬相仕帥仕相馬車 from row 0-8
            self.boards[board_id][0][0] = ChessPiece(PieceType.CHARIOT, player, BoardPosition(board_id, 0, 0))   # 車
            self.boards[board_id][0][1] = ChessPiece(PieceType.HORSE, player, BoardPosition(board_id, 1, 0))     # 馬
            self.boards[board_id][0][2] = ChessPiece(PieceType.ELEPHANT, player, BoardPosition(board_id, 2, 0))  # 相
            self.boards[board_id][0][3] = ChessPiece(PieceType.ADVISOR, player, BoardPosition(board_id, 3, 0))   # 仕
            self.boards[board_id][0][4] = ChessPiece(PieceType.GENERAL, player, BoardPosition(board_id, 4, 0))   # 帥
            self.boards[board_id][0][5] = ChessPiece(PieceType.ADVISOR, player, BoardPosition(board_id, 5, 0))   # 仕
            self.boards[board_id][0][6] = ChessPiece(PieceType.ELEPHANT, player, BoardPosition(board_id, 6, 0))  # 相
            self.boards[board_id][0][7] = ChessPiece(PieceType.HORSE, player, BoardPosition(board_id, 7, 0))     # 馬
            self.boards[board_id][0][8] = ChessPiece(PieceType.CHARIOT, player, BoardPosition(board_id, 8, 0))   # 車
            
            # Column 2 - Cannons (2 cannons placed at traditional positions)
            self.boards[board_id][2][1] = ChessPiece(PieceType.CANNON, player, BoardPosition(board_id, 1, 2))
            self.boards[board_id][2][7] = ChessPiece(PieceType.CANNON, player, BoardPosition(board_id, 7, 2))
            
            # Column 3 - Pawns (5 pawns at alternating positions like traditional)
            for row in [0, 2, 4, 6, 8]:
                self.boards[board_id][3][row] = ChessPiece(PieceType.PAWN, player, BoardPosition(board_id, row, 3))
                
        self.current_player = Player.RED
        self.eliminated_players = set()
        self.game_over = False
        self.selected_piece = None
        self.selected_pos = None
        self.update()
        
    def get_board_center(self, board_id: int) -> Tuple[float, float]:
        """Get the center coordinates of a specific board"""
        angle_rad = math.radians(self.board_angles[board_id])
        x = self.center_x + self.board_distance * math.cos(angle_rad)
        y = self.center_y + self.board_distance * math.sin(angle_rad)
        return (x, y)
        
    def get_board_rotation(self, board_id: int) -> float:
        """Get the rotation angle for a specific board"""
        # Each board is rotated to face the center
        return self.board_angles[board_id] + 180
        
    def board_to_screen(self, position: BoardPosition) -> Tuple[float, float]:
        """Convert board position to screen coordinates"""
        board_center_x, board_center_y = self.get_board_center(position.board_id)
        rotation = self.get_board_rotation(position.board_id)
        
        # Calculate position relative to board center
        x = (position.col - 2) * self.cell_size  # col 2 is center (0-4)
        y = (position.row - 4) * self.cell_size  # row 4 is center (0-8)
        
        # Apply rotation
        angle_rad = math.radians(rotation)
        cos_angle = math.cos(angle_rad)
        sin_angle = math.sin(angle_rad)
        
        rotated_x = x * cos_angle - y * sin_angle
        rotated_y = x * sin_angle + y * cos_angle
        
        # Translate to screen coordinates
        screen_x = board_center_x + rotated_x
        screen_y = board_center_y + rotated_y
        
        return (screen_x, screen_y)
        
    def screen_to_board(self, x: float, y: float) -> Optional[BoardPosition]:
        """Convert screen coordinates to board position"""
        # Check each board
        for board_id in range(3):
            board_center_x, board_center_y = self.get_board_center(board_id)
            rotation = self.get_board_rotation(board_id)
            
            # Translate to board-relative coordinates
            rel_x = x - board_center_x
            rel_y = y - board_center_y
            
            # Apply inverse rotation
            angle_rad = -math.radians(rotation)
            cos_angle = math.cos(angle_rad)
            sin_angle = math.sin(angle_rad)
            
            unrotated_x = rel_x * cos_angle - rel_y * sin_angle
            unrotated_y = rel_x * sin_angle + rel_y * cos_angle
            
            # Convert to board coordinates
            col = round(unrotated_x / self.cell_size + 2)
            row = round(unrotated_y / self.cell_size + 4)
            
            # Check if within board bounds
            if 0 <= row < self.rows and 0 <= col < self.cols:
                return BoardPosition(board_id, row, col)
                
        return None
        
    def paintEvent(self, event):
        """Paint the three chess boards and pieces"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        
        # Draw background
        painter.fillRect(self.rect(), QColor(245, 222, 179))
        
        # Draw each board
        for board_id in range(3):
            self.draw_single_board(painter, board_id)
            
        # Draw connecting lines
        self.draw_connecting_lines(painter)
        
        # Draw pieces
        font = QFont("SimSun", 18, QFont.Weight.Bold)
        painter.setFont(font)
        
        for board_id in range(3):
            for col in range(self.cols):
                for row in range(self.rows):
                    piece = self.boards[board_id][col][row]
                    if piece:
                        pos = BoardPosition(board_id, row, col)
                        x, y = self.board_to_screen(pos)
                        
                        # Highlight selected piece
                        if self.selected_pos and self.selected_pos == pos:
                            painter.setBrush(QBrush(QColor(255, 255, 0, 128)))
                            painter.setPen(QPen(Qt.GlobalColor.yellow, 3))
                            painter.drawEllipse(QPointF(x, y), 20, 20)
                        
                        # Draw piece circle
                        player_colors = {
                            Player.RED: (QColor(255, 100, 100), Qt.GlobalColor.darkRed),
                            Player.BLUE: (QColor(100, 100, 255), Qt.GlobalColor.darkBlue),
                            Player.GREEN: (QColor(100, 255, 100), Qt.GlobalColor.darkGreen)
                        }
                        
                        bg_color, text_color = player_colors[piece.player]
                        painter.setBrush(QBrush(bg_color))
                        painter.setPen(QPen(text_color, 2))
                        painter.drawEllipse(QPointF(x, y), 18, 18)
                        
                        # Draw piece character
                        painter.setPen(text_color)
                        rect = QRectF(x - 12, y - 12, 24, 24)
                        painter.drawText(rect, Qt.AlignmentFlag.AlignCenter, piece.get_char())
                        
    def draw_single_board(self, painter: QPainter, board_id: int):
        """Draw a single board grid"""
        board_center_x, board_center_y = self.get_board_center(board_id)
        rotation = self.get_board_rotation(board_id)
        
        # Save painter state
        painter.save()
        
        # Translate and rotate
        painter.translate(board_center_x, board_center_y)
        painter.rotate(rotation)
        
        # Draw board background
        bg_color = self.board_colors[board_id]
        bg_color.setAlpha(50)
        rect = QRectF(-self.board_width/2 - 10, -self.board_height/2 - 10,
                      self.board_width + 20, self.board_height + 20)
        painter.fillRect(rect, bg_color)
        
        # Draw grid lines
        pen = QPen(Qt.GlobalColor.black, 1)
        painter.setPen(pen)
        
        # Vertical lines
        for col in range(self.cols):
            x = (col - 2) * self.cell_size
            painter.drawLine(x, int(-self.board_height/2), x, int(self.board_height/2))
            
        # Horizontal lines
        for row in range(self.rows):
            y = (row - 4) * self.cell_size
            painter.drawLine(int(-self.board_width/2), y, int(self.board_width/2), y)
            
        # Draw palace (for general and advisors)
        # Palace is in rows 3-5, cols 0-2 (3x3 area around the General)
        palace_pen = QPen(Qt.GlobalColor.darkRed, 2)
        painter.setPen(palace_pen)
        
        # Palace diagonals crossing the full 3x3 area
        painter.drawLine(int(-2*self.cell_size), int(-self.cell_size),
                        int(0), int(self.cell_size))
        painter.drawLine(int(0), int(-self.cell_size),
                        int(-2*self.cell_size), int(self.cell_size))
        
        # Restore painter state
        painter.restore()
        
    def draw_connecting_lines(self, painter: QPainter):
        """Draw simple lines connecting the boards"""
        pen = QPen(Qt.GlobalColor.gray, 2, Qt.PenStyle.DashLine)
        painter.setPen(pen)
        
        # Draw lines from each board toward center
        for board_id in range(3):
            board_center_x, board_center_y = self.get_board_center(board_id)
            
            # Calculate start point (edge of board facing center)
            angle_to_center = math.radians(self.board_angles[board_id] + 180)
            start_x = board_center_x + self.board_height/2 * math.cos(angle_to_center)
            start_y = board_center_y + self.board_height/2 * math.sin(angle_to_center)
            
            painter.drawLine(QPointF(start_x, start_y), 
                           QPointF(self.center_x, self.center_y))
            
        # Draw small circle at center
        painter.setBrush(QBrush(Qt.GlobalColor.darkGray))
        painter.setPen(QPen(Qt.GlobalColor.black, 2))
        painter.drawEllipse(QPointF(self.center_x, self.center_y), 5, 5)
        
    def mousePressEvent(self, event):
        """Handle mouse clicks on the board"""
        if self.game_over:
            return
            
        if event.button() == Qt.MouseButton.LeftButton:
            pos = self.screen_to_board(event.position().x(), event.position().y())
            if pos:
                self.handle_square_click(pos)
                
    def handle_square_click(self, pos: BoardPosition):
        """Handle clicking on a board square"""
        clicked_piece = self.boards[pos.board_id][pos.col][pos.row]
        
        if self.selected_piece is None:
            # No piece selected, try to select piece
            if clicked_piece and clicked_piece.player == self.current_player:
                self.selected_piece = clicked_piece
                self.selected_pos = pos
                self.update()
        else:
            # Piece already selected
            if self.selected_pos == pos:
                # Clicked same square, deselect
                self.selected_piece = None
                self.selected_pos = None
                self.update()
            elif clicked_piece and clicked_piece.player == self.current_player:
                # Clicked own piece, select it instead
                self.selected_piece = clicked_piece
                self.selected_pos = pos
                self.update()
            else:
                # Try to move to this square
                if self.is_valid_move(self.selected_pos, pos):
                    self.make_move(self.selected_pos, pos)
                else:
                    # Invalid move, just deselect
                    self.selected_piece = None
                    self.selected_pos = None
                    self.update()
                    
    def is_valid_move(self, from_pos: BoardPosition, to_pos: BoardPosition) -> bool:
        """Check if a move is valid"""
        piece = self.boards[from_pos.board_id][from_pos.col][from_pos.row]
        if not piece:
            return False
            
        target_piece = self.boards[to_pos.board_id][to_pos.col][to_pos.row]
        
        # Can't capture own piece
        if target_piece and target_piece.player == piece.player:
            return False
            
        # Check if moving within same board or between boards
        if from_pos.board_id == to_pos.board_id:
            # Same board movement - use standard rules
            return self.is_valid_move_same_board(from_pos, to_pos, piece)
        else:
            # Cross-board movement - special rules
            return self.is_valid_move_cross_board(from_pos, to_pos, piece)
            
    def is_valid_move_same_board(self, from_pos: BoardPosition, to_pos: BoardPosition, piece: ChessPiece) -> bool:
        """Check valid movement within the same board"""
        # Similar to standard Chinese chess rules but adapted for 9x5 board
        
        if piece.piece_type == PieceType.GENERAL:
            # Must stay in palace (rows 3-5, cols 0-2)
            if not (3 <= to_pos.row <= 5 and 0 <= to_pos.col <= 2):
                return False
            # One step orthogonally
            row_diff = abs(to_pos.row - from_pos.row)
            col_diff = abs(to_pos.col - from_pos.col)
            return (row_diff == 1 and col_diff == 0) or (row_diff == 0 and col_diff == 1)
            
        elif piece.piece_type == PieceType.ADVISOR:
            # Must stay in palace (rows 3-5, cols 0-2)
            if not (3 <= to_pos.row <= 5 and 0 <= to_pos.col <= 2):
                return False
            # One step diagonally
            return (abs(to_pos.row - from_pos.row) == 1 and 
                   abs(to_pos.col - from_pos.col) == 1)
                   
        elif piece.piece_type == PieceType.ELEPHANT:
            # Cannot cross center line (row 4) - elephants stay on their side
            if to_pos.row < 4:
                return False
            # Two steps diagonally
            row_diff = to_pos.row - from_pos.row
            col_diff = to_pos.col - from_pos.col
            if abs(row_diff) != 2 or abs(col_diff) != 2:
                return False
            # Check blocking
            block_row = from_pos.row + row_diff // 2
            block_col = from_pos.col + col_diff // 2
            return self.boards[from_pos.board_id][block_col][block_row] is None
            
        elif piece.piece_type == PieceType.HORSE:
            # L-shape movement
            row_diff = to_pos.row - from_pos.row
            col_diff = to_pos.col - from_pos.col
            if not ((abs(row_diff) == 2 and abs(col_diff) == 1) or 
                    (abs(row_diff) == 1 and abs(col_diff) == 2)):
                return False
            # Check blocking
            if abs(row_diff) == 2:
                block_row = from_pos.row + row_diff // 2
                block_col = from_pos.col
            else:
                block_row = from_pos.row
                block_col = from_pos.col + col_diff // 2
            return self.boards[from_pos.board_id][block_col][block_row] is None
            
        elif piece.piece_type == PieceType.CHARIOT:
            # Straight line movement
            if from_pos.row != to_pos.row and from_pos.col != to_pos.col:
                return False
            # Check path is clear
            if from_pos.row == to_pos.row:
                start_col = min(from_pos.col, to_pos.col) + 1
                end_col = max(from_pos.col, to_pos.col)
                for col in range(start_col, end_col):
                    if self.boards[from_pos.board_id][col][from_pos.row] is not None:
                        return False
            else:
                start_row = min(from_pos.row, to_pos.row) + 1
                end_row = max(from_pos.row, to_pos.row)
                for row in range(start_row, end_row):
                    if self.boards[from_pos.board_id][from_pos.col][row] is not None:
                        return False
            return True
            
        elif piece.piece_type == PieceType.CANNON:
            # Similar to chariot but needs exactly one piece to jump over when capturing
            if from_pos.row != to_pos.row and from_pos.col != to_pos.col:
                return False
            
            target = self.boards[to_pos.board_id][to_pos.col][to_pos.row]
            pieces_between = 0
            
            if from_pos.row == to_pos.row:
                start_col = min(from_pos.col, to_pos.col) + 1
                end_col = max(from_pos.col, to_pos.col)
                for col in range(start_col, end_col):
                    if self.boards[from_pos.board_id][col][from_pos.row] is not None:
                        pieces_between += 1
            else:
                start_row = min(from_pos.row, to_pos.row) + 1
                end_row = max(from_pos.row, to_pos.row)
                for row in range(start_row, end_row):
                    if self.boards[from_pos.board_id][from_pos.col][row] is not None:
                        pieces_between += 1
                        
            if target:
                return pieces_between == 1
            else:
                return pieces_between == 0
                
        elif piece.piece_type == PieceType.PAWN:
            # Forward movement (toward center/row 0), can move sideways after crossing center
            row_diff = to_pos.row - from_pos.row
            col_diff = abs(to_pos.col - from_pos.col)
            
            # Can only move one step
            if abs(row_diff) + col_diff != 1:
                return False
                
            # Must move forward (toward row 0)
            if row_diff >= 0:
                return False
                
            # Can move sideways only after crossing row 4 (center line)
            if col_diff == 1 and from_pos.row >= 4:
                return False
                
            return True
            
        return False
        
    def is_valid_move_cross_board(self, from_pos: BoardPosition, to_pos: BoardPosition, piece: ChessPiece) -> bool:
        """Check valid movement between boards"""
        # In three-player chess, ALL pieces can move between boards
        # treating boards as if they're in straight lines, ignoring visual rotation
        
        # Check if the boards are adjacent (clockwise order: 0->1->2->0)
        board_diff = (to_pos.board_id - from_pos.board_id) % 3
        if board_diff != 1 and board_diff != 2:
            return False
            
        # General rules for cross-board movement:
        # Treat boards as straight extensions of each other
        # Any edge can connect to any edge of adjacent board
        
        target_piece = self.boards[to_pos.board_id][to_pos.col][to_pos.row]
        
        # Can't capture own piece
        if target_piece and target_piece.player == piece.player:
            return False
            
        # Now check piece-specific movement rules (treating boards as straight)
        if piece.piece_type == PieceType.GENERAL:
            # General moves one step at a time
            return True
            
        elif piece.piece_type == PieceType.ADVISOR:
            # Advisor moves diagonally
            return True
            
        elif piece.piece_type == PieceType.ELEPHANT:
            # Elephant moves exactly 2 points diagonally
            return True
            
        elif piece.piece_type == PieceType.HORSE:
            # Horse L-shaped movement across boards
            return True
            
        elif piece.piece_type == PieceType.CHARIOT:
            # Chariot straight line movement - can move between boards in straight lines
            return True
            
        elif piece.piece_type == PieceType.CANNON:
            # Cannon can move straight and jump to capture
            return True
            
        elif piece.piece_type == PieceType.PAWN:
            # Pawns can cross boards continuing their forward movement
            return True
            
        return True
        
    def make_move(self, from_pos: BoardPosition, to_pos: BoardPosition):
        """Execute a move on the board"""
        piece = self.boards[from_pos.board_id][from_pos.col][from_pos.row]
        captured_piece = self.boards[to_pos.board_id][to_pos.col][to_pos.row]
        
        # Move the piece
        self.boards[to_pos.board_id][to_pos.col][to_pos.row] = piece
        self.boards[from_pos.board_id][from_pos.col][from_pos.row] = None
        piece.position = to_pos
        
        # Check for capturing general
        if captured_piece and captured_piece.piece_type == PieceType.GENERAL:
            self.eliminated_players.add(captured_piece.player)
            
            # Check for game over
            if len(self.eliminated_players) >= 2:
                self.game_over = True
                remaining_players = set(self.board_to_player.values()) - self.eliminated_players
                winner = remaining_players.pop()
                winner_name = winner.value.capitalize()
                QMessageBox.information(self, "Game Over", f"{winner_name} wins!")
                
        # Cycle to next player who is not eliminated
        self.advance_turn()
        
        # Deselect piece
        self.selected_piece = None
        self.selected_pos = None
        
        # Emit signal
        self.piece_moved.emit(from_pos, to_pos)
        
        self.update()
        
    def advance_turn(self):
        """Advance to the next player who is not eliminated"""
        players = [Player.RED, Player.BLUE, Player.GREEN]
        current_index = players.index(self.current_player)
        
        for _ in range(3):
            current_index = (current_index + 1) % 3
            next_player = players[current_index]
            if next_player not in self.eliminated_players:
                self.current_player = next_player
                break
                
    def reset_game(self):
        """Reset the game to initial state"""
        self.setup_initial_boards()


class ThreePlayerMainWindow(QMainWindow):
    """Main window for the three-player Chinese chess game"""
    
    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):
        self.setWindowTitle("Three-Player Chinese Chess (Xiangqi)")
        self.setGeometry(100, 100, 1200, 850)
        
        # Create menu bar
        self.create_menu_bar()
        
        # Create status bar
        self.status_bar = QStatusBar()
        self.setStatusBar(self.status_bar)
        self.status_bar.showMessage("Red's turn")
        
        # Create central widget
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # Main layout
        layout = QHBoxLayout()
        splitter = QSplitter(Qt.Orientation.Horizontal)
        
        # Chess board
        self.chess_board = ThreePlayerChessBoard()
        self.chess_board.piece_moved.connect(self.on_piece_moved)
        splitter.addWidget(self.chess_board)
        
        # Right panel
        right_panel = QWidget()
        right_layout = QVBoxLayout()
        
        # Game info
        info_group = QGroupBox("Game Information")
        info_layout = QVBoxLayout()
        
        self.current_player_label = QLabel("Current Player: Red")
        self.current_player_label.setFont(QFont("Arial", 12, QFont.Weight.Bold))
        info_layout.addWidget(self.current_player_label)
        
        self.players_status_label = QLabel("Active Players: Red, Blue, Green")
        info_layout.addWidget(self.players_status_label)
        
        info_group.setLayout(info_layout)
        right_layout.addWidget(info_group)
        
        # Game controls
        controls_group = QGroupBox("Game Controls")
        controls_layout = QVBoxLayout()
        
        self.new_game_button = QPushButton("New Game")
        self.new_game_button.clicked.connect(self.new_game)
        controls_layout.addWidget(self.new_game_button)
        
        controls_group.setLayout(controls_layout)
        right_layout.addWidget(controls_group)
        
        # Move history
        history_group = QGroupBox("Move History")
        history_layout = QVBoxLayout()
        
        self.move_history = QTextEdit()
        self.move_history.setReadOnly(True)
        self.move_history.setMaximumHeight(300)
        history_layout.addWidget(self.move_history)
        
        history_group.setLayout(history_layout)
        right_layout.addWidget(history_group)
        
        # Rules info
        rules_group = QGroupBox("Three-Player Rules")
        rules_layout = QVBoxLayout()
        
        rules_text = QLabel("""
Special Three-Player Rules:
• Three 9×5 boards in triangular formation
• Players: Red, Blue, Green
• Each player has complete traditional pieces:
  - 1 General, 2 Advisors, 2 Elephants
  - 2 Horses, 2 Chariots, 2 Cannons, 5 Pawns
• Turn order rotates clockwise
• ALL pieces can move across boards!
  - Board edges are treated as continuous
  - Right edge connects to left edge
  - Bottom connects to top of next board
  - Each piece maintains its movement rules
• Win by eliminating two opponents
• Last player standing wins
        """)
        rules_text.setWordWrap(True)
        rules_text.setFont(QFont("Arial", 9))
        rules_layout.addWidget(rules_text)
        
        rules_group.setLayout(rules_layout)
        right_layout.addWidget(rules_group)
        
        right_panel.setLayout(right_layout)
        right_panel.setMaximumWidth(350)
        splitter.addWidget(right_panel)
        
        layout.addWidget(splitter)
        central_widget.setLayout(layout)
        
    def create_menu_bar(self):
        """Create the menu bar"""
        menubar = self.menuBar()
        
        # Game menu
        game_menu = menubar.addMenu('Game')
        
        new_game_action = QAction('New Game', self)
        new_game_action.setShortcut('Ctrl+N')
        new_game_action.triggered.connect(self.new_game)
        game_menu.addAction(new_game_action)
        
        game_menu.addSeparator()
        
        exit_action = QAction('Exit', self)
        exit_action.setShortcut('Ctrl+Q')
        exit_action.triggered.connect(self.close)
        game_menu.addAction(exit_action)
        
        # Help menu
        help_menu = menubar.addMenu('Help')
        
        about_action = QAction('About', self)
        about_action.triggered.connect(self.show_about)
        help_menu.addAction(about_action)
        
    def on_piece_moved(self, from_pos: BoardPosition, to_pos: BoardPosition):
        """Handle piece movement"""
        # Log the move
        board_names = ["Red", "Blue", "Green"]
        from_board = board_names[from_pos.board_id]
        to_board = board_names[to_pos.board_id]
        
        if from_pos.board_id == to_pos.board_id:
            move_text = f"{from_board}: ({from_pos.row},{from_pos.col}) → ({to_pos.row},{to_pos.col})"
        else:
            move_text = f"{from_board}({from_pos.row},{from_pos.col}) → {to_board}({to_pos.row},{to_pos.col})"
            
        self.move_history.append(move_text)
        
        # Update status
        self.update_game_status()
        
    def update_game_status(self):
        """Update the game status display"""
        player_name = self.chess_board.current_player.value.capitalize()
        self.current_player_label.setText(f"Current Player: {player_name}")
        self.status_bar.showMessage(f"{player_name}'s turn")
        
        # Update active players
        all_players = {Player.RED, Player.BLUE, Player.GREEN}
        active_players = all_players - self.chess_board.eliminated_players
        active_names = [p.value.capitalize() for p in active_players]
        self.players_status_label.setText(f"Active Players: {', '.join(active_names)}")
        
    def new_game(self):
        """Start a new game"""
        self.chess_board.reset_game()
        self.move_history.clear()
        self.update_game_status()
        self.status_bar.showMessage("Red's turn - New game started")
        
    def show_about(self):
        """Show about dialog"""
        QMessageBox.about(
            self,
            "About Three-Player Chinese Chess",
            "Three-Player Chinese Chess (Xiangqi)\n\n"
            "A unique three-player variant with:\n"
            "• Three 9×5 boards in triangular formation\n"
            "• Three players: Red, Blue, and Green\n"
            "• Cross-board movement for some pieces\n"
            "• Win by eliminating two opponents\n\n"
            "Based on traditional Chinese chess rules\n"
            "adapted for three-player gameplay."
        )


def main():
    """Main function to run the three-player Chinese chess game"""
    app = QApplication(sys.argv)
    
    # Set application properties
    app.setApplicationName("Three-Player Chinese Chess")
    app.setOrganizationName("Chess Games")
    
    # Create and show main window
    window = ThreePlayerMainWindow()
    window.show()
    
    # Run the application
    sys.exit(app.exec())


if __name__ == "__main__":
    main() 